#include "Player.h"

// 构造（玩家名字）
Player::Player(CStrRef name)
{
    this->SetName(name);         // 名字
    this->SetSymbol("🧙");       // 图标
    this->SetAttack(500);        // 初始攻击力
    this->SetHP(2000);           // 初始血量
    this->SetDefend(300);        // 初始防御力
    this->GetLocation().Setx(0); // 初始x坐标
    this->GetLocation().Sety(0); // 初始y坐标
    this->SetGold(2000);         // 初始金币
    this->SetDiamond(50);        // 初始钻石
    this->SetExp(0);             // 初始经验
    this->SetLevel(50);          // 初始等级
    this->SetAttrPoint(0);       // 初始属性
    this->SetPower(20);          // 初始暴击率
    this->SetDodge(20);          // 初始闪避率
    this->SetFloor(1);
    w = nullptr;
    a = nullptr;
    m = nullptr;
}

// 移动
bool Player::Move()
{
    std::cout << "===================================================" << std::endl;
    std::cout << "请输入玩家操作(w:上 s:下 a:左 d:右 p:查看我的属性 b:打开背包 v:存档):";
    char choice = -1;
    std::cin >> choice;
    while (getchar() != '\n');
    switch (choice)
    {
    case 'w':
        // 上移
        GetLocation().up();
        break;
    case 's':
        // 下移
        GetLocation().down();
        // 空气墙
        if (GetLocation().Gety() >= MaxHeight)
            GetLocation().Sety(MaxHeight - 1);
        break;
    case 'a':
        // 左移
        GetLocation().left();
        break;
    case 'd':
        // 右移
        GetLocation().right();
        // 空气墙
        if (GetLocation().Getx() >= MaxWidth)
            GetLocation().Setx(MaxWidth - 1);
        break;
    case 'p':
        // 属性界面
        AttrInterface();
        break;
    case 'b':
        // 展示背包
        showBag();
        break;
    case 'v':
        return true;
    default:
        break;
    }
    return false;
}

// 升级
void Player::LevelUp()
{
    // 经验值大于等于100就升一级
    while (GetExp() >= 100)
    {
        // 清空经验值
        SetExp(GetExp() - 100);
        // 等级 +1
        Level++;
        // 属性 +5
        AttrPoint += 5;
        std::cout << "恭喜升级！升到|" << Level << "|级!\n";
    }
}

// 属性界面
void Player::AttrInterface()
{
    while (1)
    {
        system("clear");
        std::cout << "当前可分配的属性点是:|" << AttrPoint << "|" << std::endl;
        std::cout << "1、攻击力:" << GetAttack() << std::endl;
        std::cout << "2、防御力:" << GetDefend() << std::endl;
        std::cout << "3、血量:" << MaxHP << std::endl;
        std::cout << "4、暴击率" << GetPower() << std::endl;
        std::cout << "5、闪避率:" << GetDodge() << std::endl;
        std::cout << "6、退出:" << std::endl;
        // 选择选项
        int choice;
        // 属性加点数值
        int number;
        std::cout << "请选择你要分配的属性:";
        std::cin >> choice;
        // 如果选6就直接退出
        if (choice == 6)
            return;
        if (choice <= 0 || choice > 6)
        {
            std::cout << "当前没有该属性，请重新选择:" << std::endl;
            sleep(1);
            continue;
        }

        std::cout << "请选择你要加点的数值:";
        std::cin >> number;
        // 分配点数不符合规则
        if (number > AttrPoint || number < 0)
        {
            std::cout << "分配点数不符合规则，请重新选择:" << std::endl;
            sleep(1);
            continue;
        }

        auto operation = AttrFactory::CreateOperation(choice);
        if (operation)
        {
            operation->Operation(*this, number);
            std::cout << "分配成功!\n";
            // 刷新属性
            AttrPoint -= number;
            sleep(1);
        }
        // 选择要加点的属性
        // switch (choice)
        // {
        // case 1:
        //     // 攻击力加点
        //     SetAttack(GetAttack() + number * 10);
        //     break;
        // case 2:
        //     // 防御力加点
        //     SetDefend(GetDefend() + number * 10);
        //     break;
        // case 3:
        //     // 血量加点
        //     MaxHP = MaxHP + number * 100;
        //     break;
        // case 4:
        //     // 暴击率加点（不超过80%）
        //     if (GetPower() + number > 80)
        //         number = 80 - GetPower();
        //     SetPower(GetPower() + number);
        //     break;
        // case 5:
        //     // 闪避率加点（不超过50%）
        //     if (GetDodge() + number > 50)
        //         number = 50 - GetDodge();
        //     SetDodge(GetDodge() + number);
        //     break;
        // default:
        //     break;
        // }       
    }
}

// 秀一下玩家
void Player::show()
{
    std::cout << "===================================================" << std::endl;
    std::cout << "                玩家姓名🧙:|" << GetName() << "|" << std::endl;
    std::cout << "===================================================" << std::endl;
    std::cout << "血量❤️:|" << GetHP() << "/" << MaxHP << "|"
              << "    攻击力🗡️:|" << GetAttack() << "|"
              << "    防御力🛡️:|" << GetDefend() << "|"
              << std::endl;
    std::cout << "等级🎓:|" << GetLevel() << "|"
              << "          经验值🪄:|" << GetExp() << "|"
              << "      属性值🎨:|" << GetAttrPoint() << "|"
              << std::endl;
    std::cout << "金币🪙:|" << GetGold() << "|"
              << "         钻石💎:|" << GetDiamond() << "|"
              << std::endl;
    std::cout << "暴击率💥:|" << GetPower() << "|"
              << "        闪避率✨:|" << GetDodge() << "|"
              << std::endl;
    // 如果装上了武器就显示
    if (w)
        std::cout << "武器🥊:|" << w->GetName() << "|" << std::endl;
    // 如果装上了防具就显示
    if (a)
        std::cout << "防具🎭:|" << a->GetName() << "|" << std::endl;
}

// 秀一下背包
void Player::showBag()
{
    while (1)
    {
        system("clear");
        show();
        std::cout << std::endl;
        std::cout << "=========================🎒背包==========================" << std::endl;
        int i = 0;
        for (; i < bag.size(); i++)
        {
            std::cout << i + 1 << "、";
            bag[i]->show();
        }
        std::cout << i + 1 << "、" << "卸下武器" << std::endl;
        std::cout << i + 2 << "、" << "卸下防具" << std::endl;
        std::cout << i + 3 << "、" << "退出" << std::endl;
        std::cout << "请选择你要操作的物品:" << std::endl;
        int choice = 0;
        std::cin >> choice;
        // 检查输入流是否错误
        if (std::cin.fail() || choice < 1 || choice > i + 3)
        {
            if (std::cin.fail())
            {
                std::cin.clear();                                                   // 清除错误标志
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 丢弃无效输入
            }
            std::cout << "没有该选项哦，请重新选择!" << std::endl;
            sleep(1);
            continue;
        }
        if (choice == i + 1)
        {
            if (w)
            {
                std::cout << "已卸下武器" << std::endl;
                w = nullptr;
                sleep(1);
            }
            else
            {
                std::cout << "当前还没有装备武器哦" << std::endl;
                sleep(1);
                continue;
            }
        }
        else if (choice == i + 2)
        {
            if (a)
            {
                std::cout << "已卸下防具" << std::endl;
                a = nullptr;
                sleep(1);
            }
            else
            {
                std::cout << "当前还没有装备防具哦" << std::endl;
                sleep(1);
                continue;
            }
        }
        else if (choice == i + 3)
            return;

        // 这个裸指针只是用来判断是不是武器，不需要拿出来用
        // 尝试将 bag[choice - 1].get() 的结果动态转换为 Weapon* 类型
        // 如果转换成功（即 ptr 不为 nullptr），则执行 if 语句块中的代码
        // 如果转换失败（即 ptr 为 nullptr），则跳过 if 语句块
        else
        {
            if (auto ptr = dynamic_cast<Weapon *>(bag[choice - 1].get()); ptr != nullptr)
            {
                std::cout << "是否确定要更换武器？(y/n)";
                char c = 0;
                std::cin >> c;
                // 不区分大小写
                if (c == 'y' || c == 'Y')
                {
                    // 如果武器指针不为空，说明玩家正携带着武器，将原来的武器卸下
                    if (w)
                    {
                        std::cout << "已卸下|" << w->GetName() << "|" << std::endl;
                        SetAttack(GetAttack() - w->GetAttack());
                    }
                    // 把新武器装上
                    w = ptr;
                    std::cout << "成功装备|" << w->GetName() << "|" << std::endl;
                    SetAttack(GetAttack() + w->GetAttack());
                    sleep(1);
                }
            }

            if (auto ptr = dynamic_cast<Armor *>(bag[choice - 1].get()); ptr != nullptr)
            {
                std::cout << "是否确定要更换防具？(y/n)";
                char c = 0;
                std::cin >> c;
                // 不区分大小写
                if (c == 'y' || c == 'Y')
                {
                    // 如果防具指针不为空，说明玩家正穿着防具，将原来的防具卸下
                    if (a)
                    {
                        std::cout << "已卸下|" << a->GetName() << "|" << std::endl;
                        SetDefend(GetDefend() - a->GetDefend());
                    }
                    // 把新防具装上
                    a = ptr;
                    std::cout << "成功装备|" << a->GetName() << "|" << std::endl;
                    SetDefend(GetDefend() + a->GetDefend());
                    sleep(1);
                }
            }

            if (auto ptr = dynamic_cast<Medicine *>(bag[choice - 1].get()); ptr != nullptr)
            {
                std::cout << "是否确定要服用药水？(y/n)";
                char c = 0;
                std::cin >> c;
                // 不区分大小写
                if (c == 'y' || c == 'Y')
                {
                    // 喝药水
                    m = ptr;
                    if (GetHP() == MaxHP)
                    {
                        std::cout << "血量已达上限哦!" << std::endl;
                        sleep(1);
                    }
                    else
                    {
                        std::cout << "已服用|" << m->GetName() << "|" << std::endl;
                        SetHP(std::min(GetHP() + m->GetHP(), MaxHP));
                        bag.erase(bag.begin() + (choice - 1));
                        sleep(1);
                    }
                }
            }
        }
    }
}

// 塞入背包
void Player::InsertBag(const PropPtr &ptr)
{
    // 不管是武器、防具还是药品，这个接口都可以用，不用改
    bag.push_back(ptr->clone());
}


// 将玩家信息存入容器
std::vector<std::string> Player::GetPlayerInfo(int FloorFlag)
{
    std::vector<std::string> PlayerInfo;
    PlayerInfo.push_back(GetName() + " " + GetSymbol() + " " + std::to_string(GetAttack())
                + " " + std::to_string(GetHP()) + " " + std::to_string(GetDefend())
                + " " + std::to_string(GetLocation().Getx()) + " " + std::to_string(GetLocation().Gety())
                + " " + std::to_string(GetGold()) + " " + std::to_string(GetDiamond())
                + " " + std::to_string(GetExp()) + " " + std::to_string(GetLevel())
                + " " + std::to_string(GetAttrPoint()) + " " + std::to_string(GetPower())
                + " " + std::to_string(GetDodge()) + " " + std::to_string(GetFloor()));
    return PlayerInfo;
}

// 将背包信息存入容器
std::vector<std::string> Player::GetBagInfo()
{
    std::vector<std::string> BagInfo;
    for(auto &a : GetBag())
    {
        std::string ite;
        for(auto &b : a->GetPropInfo())
        {
            ite += b + " ";
        }
        BagInfo.push_back(ite);
    }
    return BagInfo;
}

// 写入玩家信息
void Player::WriteInPlayerInfo(std::string &fileName)
{
    auto playerInfo = GetPlayerInfo(FloorFlag);
    std::string playerFilePath = "./存档/" + GetName() + "/" + fileName + "/Player.txt";
    FileTools::WriteLine(playerFilePath, playerInfo);
}

// 写入背包信息
void Player::WriteInBagInfo(std::string &fileName)
{
    auto bagInfo = GetBagInfo();
    std::string bagFilePath = "./存档/" + GetName() + "/" + fileName + "/Bag.txt";
    FileTools::WriteLine(bagFilePath, bagInfo);
}

// 读取背包信息
void Player::ReadBagInfo(const std::string &fileName)
{
    auto vec = FileTools::ReadLine("./存档/" + GetName() + "/" + fileName + "/Bag.txt");
    for(int i = 0; i < vec.size() ; i++)
    {
        StdMyString s(vec[i].c_str());
        MyStringList l = s.split(" ");
        if(l[0] == "Weapon")
        {
            GetBag().push_back(std::make_shared<Weapon>(l[1].c_str(),(int)l[2],(int)l[3],(int)l[4]));
            if((int)l[4] == 1)
            {
                w = dynamic_cast<Weapon *>(bag[bag.size() - 1].get());
            }
        }
        if(l[0] == "Armor")
        {
            GetBag().push_back(std::make_shared<Armor>(l[1].c_str(),(int)l[2],(int)l[3],(int)l[4]));
            if((int)l[4] == 1)
            {
                a = dynamic_cast<Armor *>(bag[bag.size() - 1].get());
            }
        }
        if(l[0] == "Medicine")
        {
            GetBag().push_back(std::make_shared<Medicine>(l[1].c_str(),(int)l[2],(int)l[3],(int)l[4]));
        }  
    }
}

// 删除存档
void Player::RemoveFile(const std::string &fileName)
{
    FileTools::RemoveDir("./存档/" + GetName() + "/" + fileName + "/Bag.txt");
    FileTools::RemoveDir("./存档/" + GetName() + "/" + fileName + "/Box.txt");
    FileTools::RemoveDir("./存档/" + GetName() + "/" + fileName + "/Monster.txt");
    FileTools::RemoveDir("./存档/" + GetName() + "/" + fileName + "/Player.txt");

    FileTools::SetTxt("./存档/" + GetName() + "/" + fileName + "/Bag.txt");
    FileTools::SetTxt("./存档/" + GetName() + "/" + fileName + "/Box.txt");
    FileTools::SetTxt("./存档/" + GetName() + "/" + fileName + "/Monster.txt");
    FileTools::SetTxt("./存档/" + GetName() + "/" + fileName + "/Player.txt");
}
